/* Project: Side Scrolling Shooter
 * The main game class. Handles projectile firing and most collisions.
 * Last Update: 4/9/11,9:53PM
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Project1
{
    // 3 Game states
    public enum GameState
    {
        StartScreen,
        RunningGame,
        EndScreen
    }

    /******************************************** Game1 Class *******************************************/

    public class Game1 : Microsoft.Xna.Framework.Game
    {

        // Variables for the Player:
        private Vector2 playerstart; // Player starting location
        Player thePlayer;
        private float missileCountdown, bombCountdown; // Timers for missiles/bombs
        KeyboardState k;
        Keys missileButton, bombButton; // Buttons to launch missiles/bombs
        Keys pause; // Might not be used

        // Global variables for the game:
        GameState currentState;
        public float dt { get; set; } // Change in time
        public int borderRightX; // Maximum X
        public int borderLeftX; // Minimum X
        public int borderY; // Maximum Y
        public int currentScore { get; set; } // Current score
        public int finalScore;
        SpriteFont Font1;
        Vector2 drawScore, drawHealth; // where to draw the score and health

        /* Construct enemies, bullets, missiles, bombs, and
         * explosions by adding new ones to these lists:
         */
        public List<Enemy> Enemies;
        public List<EnemyBullet> EnemyBullets { get; set; } // (Enemy class gets access)
        public List<PlayerMissile> PlayerMissiles;
        public List<PlayerBomb> PlayerBombs;
        public List<BombExplosion> BombExplosions;

        // Visuals:
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D startScreen, endScreen;
        // Texture2D pauseScreen;
     
        /********************************* FUNCTIONS **************************************/
        
        // Game1 constructor class
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 100 / 60);
            IsFixedTimeStep = true;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Add player to game
            thePlayer = new Player(this, playerstart);
            Components.Add(thePlayer);

            // Set values for countdowns (subject to change)
            bombCountdown = 50;
            missileCountdown = 50;

            // Set values for keys (subject to change)
            missileButton = Keys.Space;
            bombButton = Keys.LeftShift;

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            startScreen = Content.Load<Texture2D>("startGame");
            endScreen = Content.Load<Texture2D>("endGame");
            Font1 = Content.Load<SpriteFont>("Courier New");
            drawScore = new Vector2(300, 5);
            drawHealth = new Vector2(500, 5);

            /* Maximum X borders are slightly wider than screen, so objects don't disappear 
             *  as soon as they touch the edge of the screen.
             */
            borderLeftX = -20; // Subject to change
            borderRightX = Window.ClientBounds.Width - borderLeftX;
            borderY = Window.ClientBounds.Height;


            // TODO: use this.Content to load your game content here
        }


        private void UpdateSplashScreen()
        {
            KeyboardState keyState = Keyboard.GetState();
            if (keyState.IsKeyDown(Keys.Enter))
            {
                currentState = GameState.RunningGame;

            }
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        // Projectile controls
        public void FireMissile()
        {
            // Creates new missile in front of player
            Vector2 pos = thePlayer.Position + new Vector2(5, 0);
            PlayerMissiles.Add(new PlayerMissile(this, PlayerMissiles, pos));
        }

        public void DropBomb()
        {
            // Creates new bomb below player
            Vector2 pos = thePlayer.Position + new Vector2(0, 5);
            PlayerBombs.Add(new PlayerBomb(this, PlayerBombs, pos));
        }

        // Reset the game
        public void ResetGame()
        {
            Enemies.Clear();
            EnemyBullets.Clear();
            PlayerMissiles.Clear();
            PlayerBombs.Clear();
            BombExplosions.Clear();
            
            currentScore = 0;
            thePlayer.Health = 100;
            thePlayer.IsAlive = true;
            thePlayer.Position = playerstart;

            currentState = GameState.EndScreen;
        }


        //**********************************************************************
        //****************************** UPDATE ********************************
        //**********************************************************************
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Check: Is the game not running?
            if (currentState != GameState.RunningGame)
                UpdateSplashScreen();
            else
            {
                // THINGS TO DO WHILE GAME IS RUNNING
                k = Keyboard.GetState();
                dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

                // Check: Exit game?
                if (k.IsKeyDown(Keys.Escape)) currentState = GameState.EndScreen;

                // Check: Is player alive?
                if (!thePlayer.IsAlive)
                {   
                    finalScore = currentScore;
                    ResetGame();
                }

                // PROJECTILE CONTROLS          
                                                                                
                // Firing missiles: delay time between fires
                if (missileCountdown > 0)
                {
                    missileCountdown -= 0.0075f * dt;
                }
                else if (k.IsKeyDown(missileButton) && missileCountdown <= 0)
                {
                    FireMissile();
                    missileCountdown = 50;
                }

                // Dropping bombs: delay time between drops
                if (bombCountdown > 0)
                {
                    bombCountdown -= 0.005f * dt;
                }
                else if (k.IsKeyDown(bombButton) && bombCountdown <= 0)
                {
                    DropBomb();
                    bombCountdown = 50;
                }
                // ----------------------------------------------------------------


                // COLLISION HANDLING
                // ----------------------------------------------------------------
                // Missile-> Enemy collision handling
                foreach (PlayerMissile m in PlayerMissiles)
                {
                    // Check if off-screen
                    if (m.posX > borderRightX) m.Die();

                    foreach (Enemy e in Enemies)
                    {
                        // Logic
                        if (m.HitsEnemy(e))
                        {
                            e.Die();
                            m.Die();
                            currentScore += e.pointValue;
                        }
                    }
                    return;
                }

                // BombExplosion-> Enemy collision handling
                foreach (BombExplosion be in BombExplosions)
                {
                    foreach (Enemy e in Enemies)
                    {
                        // Logic
                        if (be.CollideWithEnemy(e))
                        {
                            e.Die();
                            currentScore += e.pointValue * 2 / 3;
                        }
                    }
                    return;
                }

                // Enemy-> Player collision handling
                foreach (Enemy e in Enemies)
                {
                    // Check if off-screen
                    if (e.posX < borderLeftX) e.Die();

                    // Collision with player?
                    if (e.CollideWithPlayer())
                    {
                        e.Die();
                        thePlayer.Damage(20);
                        currentScore += e.pointValue / 5;
                    }
                    return;

                    // Attack logic?
                }

                // EnemyBullet-> Player collision handling
                foreach (EnemyBullet eb in EnemyBullets)
                {
                    // Check if off-screen
                    if (eb.posX < borderLeftX) eb.Die();
                    else if (eb.posX > borderRightX) eb.Die();

                    // Collision with player?
                    if (eb.HitsPlayer(thePlayer))
                    {
                        eb.Die();
                        thePlayer.Damage(10);
                    }
                    return;
                }
                // ----------------------------------------------------------------

                // Enemy generation
                // ----------------------------------------------------------------
                // ----------------------------------------------------------------
            }

            base.Update(gameTime);
        }

        
        //************************************************************************
        //***********************           DRAW        **************************
        //************************************************************************
        
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            // When the game is not running, draw the start or end screen
            spriteBatch.Begin();
            if (currentState != GameState.RunningGame)
            {

                if (currentState == GameState.StartScreen)
                    spriteBatch.Draw(startScreen, Vector2.Zero, null, Color.White);
                else
                {
                    spriteBatch.Draw(endScreen, Vector2.Zero, null, Color.White);
                    spriteBatch.DrawString(Font1, finalScore.ToString(), drawScore, Color.DarkGreen);

                }
                spriteBatch.End();
            }


            spriteBatch.DrawString(Font1, currentScore.ToString(), drawScore, Color.Black);
            spriteBatch.DrawString(Font1, thePlayer.Health.ToString(), drawScore, Color.DarkRed);
            spriteBatch.End();

            // Logic for drawing the Player is in the Player.cs file

            base.Draw(gameTime);
        }
    }
}
